<script setup lang="ts">
import { isDev, PACS_SETTING } from '@/config/config'
import {
  Enums,
  RenderingEngine,
  Types,
  volumeLoader,
  utilities, setVolumesForViewports, CONSTANTS
} from '@cornerstonejs/core'
import { adaptersSEG } from '@cornerstonejs/adapters'
import { metaData } from '@cornerstonejs/core'
import { api } from 'dicomweb-client'
import { onMounted, reactive, ref, watchEffect } from 'vue'
import * as cornerstoneTools from '@cornerstonejs/tools'
import { initDemo, createImageIdsAndCacheMetaData } from '@/helpers/index.js'
import {
  StackScrollMouseWheelTool,
  ToolGroupManager,
  SegmentationDisplayTool,
  ZoomTool,
  TrackballRotateTool
} from '@cornerstonejs/tools'
import FourCorner from '@/components/FourCorner.vue'
import { useFourCorner } from '@/hooks/useFourCorner'
import { FOUR_CORNER_SHOW_NAME } from '@/types/types'
import Controls from '@/components/Controls.vue'

const idPrefix = 'load-segment-volume'
const uuid = utilities.uuidv4()
let renderingEngineId = `${idPrefix}-renderingEngineId-${uuid}`
let volumeId = `${idPrefix}-volumeId-${uuid}`
const viewportId1 = `${idPrefix}-viewportId1-${uuid}`
const viewportId2 = `${idPrefix}-viewportId2-${uuid}`

const toolGroupId = `${idPrefix}-toolGroupId-${uuid}`
const segmentationId = 'segmentation-image-volume:' + uuid
const renderContainerRef = ref(null)
const surfaceRenderRef = ref(null)
const { ViewportType } = Enums
const { VOLUME_NEW_IMAGE } = Enums.Events
const { cornerVal, updateCornerVal } = useFourCorner([viewportId1])
let renderingEngine
let imageIds
let volume
let toolGroup

const {
  segmentation,
  Enums: csToolsEnums
} = cornerstoneTools

const { SegmentationRepresentations, MouseBindings } = csToolsEnums

async function getImageIds() {
  const params = {
    StudyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    SeriesInstanceUID: '1.3.12.2.1107.5.2.32.35162.1999123112191238897317963.0.0.0',
    wadoRsRoot: isDev() ? `/seg-dicom-web` : 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  }
  imageIds = await createImageIdsAndCacheMetaData(params)
}

async function loadSegment() {
  const segParams = {
    studyInstanceUID: '1.3.12.2.1107.5.2.32.35162.30000015050317233592200000046',
    seriesInstanceUID: '1.2.276.0.7230010.3.1.3.296485376.8.1542816659.201008',
    sopInstanceUID: '1.2.276.0.7230010.3.1.4.296485376.8.1542816659.201009',
    wadoRsRoot: isDev() ? `/seg-dicom-web` : 'https://d33do7qe4w26qo.cloudfront.net/dicomweb'
  }
  const arrayBuffer = await retrieveDicomData(segParams)
  await loadSegmentation(arrayBuffer)
}

const loadSegmentation = async (arrayBuffer) => {
  const generateToolState =
    await adaptersSEG.Cornerstone3D.Segmentation.generateToolState(
      imageIds,
      arrayBuffer,
      metaData
    )

  const derivedVolume = await addSegmentationsToState()
  //
  const derivedVolumeScalarData = derivedVolume.getScalarData()
  //
  derivedVolumeScalarData.set(
    new Uint8Array(generateToolState.labelmapBufferArray[0])
  )
}

async function addSegmentationsToState() {
  const segmentationVolume = await volumeLoader.createAndCacheDerivedSegmentationVolume(volumeId, {
    volumeId: segmentationId
  })
  segmentation.addSegmentations([
    {
      segmentationId: segmentationId,
      representation: {
        type: csToolsEnums.SegmentationRepresentations.Labelmap,
        data: {
          volumeId: segmentationId
        }
      }
    }
  ])
  // Add the segmentation representation to the toolgroup
  await segmentation.addSegmentationRepresentations(toolGroupId, [
    {
      segmentationId,
      type: csToolsEnums.SegmentationRepresentations.Labelmap
    }
  ])

  //
  return segmentationVolume
}

function retrieveDicomData({ studyInstanceUID, seriesInstanceUID, sopInstanceUID, wadoRsRoot }) {
  const client = new api.DICOMwebClient({
    url: wadoRsRoot as string,
    singlepart: true,
    headers: PACS_SETTING.OpenAuth ? {
      'Authorization': 'Basic ' + btoa(PACS_SETTING.username + ':' + PACS_SETTING.password)
    } : {}
  })
  const options = {
    studyInstanceUID,
    seriesInstanceUID,
    sopInstanceUID
  }
  return client.retrieveInstance(options)
}

const initTools = () => {
  toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
  toolGroup.addTool(StackScrollMouseWheelTool.toolName)
  toolGroup.addTool(SegmentationDisplayTool.toolName)
  toolGroup.addTool(ZoomTool.toolName)
  toolGroup.addTool(TrackballRotateTool.toolName)

  toolGroup.setToolEnabled(SegmentationDisplayTool.toolName)

}

const initRender = async () => {
  renderingEngine = new RenderingEngine(renderingEngineId)
  const viewportInputArray = [{
    viewportId: viewportId1,
    type: ViewportType.ORTHOGRAPHIC,
    element: renderContainerRef.value,
    defaultOptions: {
      orientation: Enums.OrientationAxis.AXIAL,
      background: <Types.Point3>[0, 0, 0]
    }
  },
    {
      viewportId: viewportId2,
      type: ViewportType.VOLUME_3D,
      element: surfaceRenderRef.value,
      defaultOptions: {
        // background: <Types.Point3>[0.2, 0, 0.2]
      }
    }
  ]
  renderingEngine.setViewports(viewportInputArray)
  toolGroup.addViewport(viewportId1, renderingEngineId)
  toolGroup.addViewport(viewportId2, renderingEngineId)
  volume.load()
  await setVolumesForViewports(
    renderingEngine,
    [{ volumeId }],
    [viewportId1, viewportId2]
  )
  const viewport3d = renderingEngine.getViewport(viewportId2)
  const volumeActor = viewport3d.getDefaultActor().actor as Types.VolumeActor
  // 这里和体绘制采用的参数好像一样。
  utilities.applyPreset(
    volumeActor,
    CONSTANTS.VIEWPORT_PRESETS.find(
      (preset) => preset.name === 'CT-Bone'
    ) as any
  )
  const renderer = viewport3d.getRenderer()
  renderer.getActiveCamera().elevation(-70)
  viewport3d.setCamera({ parallelScale: 300 })
  renderingEngine.renderViewports([viewportId1, viewportId2])
}

async function createVolume() {
  volume = await volumeLoader.createAndCacheVolume(volumeId, {
    imageIds
  })
}

const onWatch = () => {
  watchEffect(() => {
    segmentation.config.setToolGroupSpecificConfig(toolGroupId, {
      renderInactiveSegmentations: true,
      representations: {
        [SegmentationRepresentations.Labelmap]: {
          renderFill: true,
          renderOutline: true,
          outlineWidthActive: labelSetting.thickness,
          fillAlpha: labelSetting.fillOpacity,
          outlineOpacity: labelSetting.outlineOpacity
        }
      }
    })
  })
  watchEffect(() => {
    const activeView = activeViewRef.value
    if (activeView === viewportId1) {
      toolGroup.setToolActive(StackScrollMouseWheelTool.toolName)
      toolGroup.setToolDisabled(TrackballRotateTool.toolName)

      toolGroup.setToolActive(ZoomTool.toolName, {
        bindings: [
          {
            mouseButton: MouseBindings.Secondary // Right Click
          }
        ]
      })
    } else if (activeView === viewportId2) {
      toolGroup.setToolDisabled(StackScrollMouseWheelTool.toolName)
      toolGroup.setToolActive(TrackballRotateTool.toolName, {
        bindings: [
          {
            mouseButton: MouseBindings.Primary
          }
        ]
      })
      toolGroup.setToolActive(ZoomTool.toolName, {
        bindings: [
          {
            mouseButton: MouseBindings.Secondary // Right Click
          }
        ]
      })
    }
  })
}


onMounted(async () => {
  await initDemo()
  initTools()
  listenEvent()
  await getImageIds()
  await createVolume()
  await loadSegment()
  await initRender()
  onWatch()
})

const listenEvent = () => {
  (renderContainerRef.value as any).addEventListener(VOLUME_NEW_IMAGE, ((
    evt: Types.EventTypes.VolumeNewImageEvent
  ) => {
    updateCornerVal(viewportId1, {
      [FOUR_CORNER_SHOW_NAME.INDEX]: evt.detail.imageIndex,
      [FOUR_CORNER_SHOW_NAME.TOTAL]: evt.detail.numberOfSlices
    })
  }) as EventListener)
}

const labelSetting = reactive({
  thickness: 1,
  outlineOpacity: 1,
  fillOpacity: 1
})


const activeViewRef = ref(viewportId1)


</script>

<template>
  <div class="w-full h-[600px] flex justify-around">

    <div class="flex-1 h-[400px]  relative border-4"
         :class="[activeViewRef === viewportId1 ?'border-amber-500' :'border-transparent']"
         @click="activeViewRef = viewportId1"
         ref="renderContainerRef">
      <four-corner :fourCornerVal="cornerVal[viewportId1]" />
    </div>

    <div class="flex-1 h-full border-4"
         @click="activeViewRef = viewportId2"
         :class="[activeViewRef === viewportId2 ?'border-amber-500' :'border-transparent']"
         ref="surfaceRenderRef"></div>

    <div class="w-[200px]">
      <controls
        v-model:thickness="labelSetting.thickness"
        v-model:outlineOpacity="labelSetting.outlineOpacity"
        v-model:fillOpacity="labelSetting.fillOpacity"
      />
    </div>
  </div>
</template>

<style scoped>

</style>
